type EventHandler = (...args: any[]) => void

/** api请求成功 */
export const api_success = Symbol('API:SUCCESS')
/** api请求无权限 */
export const api_un_auth = Symbol('API:UN_AUTH')
/** api请求无效 */
export const api_invalid = Symbol('API:INVALID')
/** api请求失败 */
export const api_fail = Symbol('API:FAIL')
/** 路由变化 */
export const router_change = Symbol('ROUTER:CHANGE')
/** 菜单加载 */
export const menu_loading = Symbol('MENU:LOADING')
/** 显示加载 */
export const show_loading = Symbol('SHOW_LOADING')

/**
 * 事件中心；
 * 利用发布订阅模式，路由route、界面vue、仓库Store、网络API通讯等主要的模块解除强耦合，实现事件监听和触发；
 */
class EventEmitter {
  // 定义一个私有变量，用于存储事件监听器
  private listeners: Record<symbol, Set<EventHandler>> = {
    [api_success]: new Set(),
    [api_un_auth]: new Set(),
    [api_invalid]: new Set(),
    [api_fail]: new Set(),
    [router_change]: new Set(),
    [menu_loading]: new Set(),
    [show_loading]: new Set()
  }

  /**
   * 用于添加事件监听器
   * @param eventName 事件名称
   * @param listener 监听器回调函数
   */
  on(eventName: symbol, listener: EventHandler) {
    // 将监听器添加到对应事件的监听器集合中
    this.listeners[eventName].add(listener)
  }

  /**
   * 用于触发事件
   * @param eventName 事件名称
   * @param args 传递给监听器的参数
   */
  emit(eventName: symbol, ...args: any[]) {
    // 遍历对应事件的监听器集合，依次调用监听器
    this.listeners[eventName]?.forEach((handler) => {
      handler(...args)
    })
  }

  /**
   * 移除事件监听器
   * @param eventName 事件名称
   * @param handler 处理者函数
   */
  off(eventName: symbol, handler: EventHandler) {
    // 如果事件监听器存在
    if (this.listeners[eventName]) {
      // 从事件监听器中删除指定的监听器
      this.listeners[eventName].delete(handler)
    }
  }

  /**
   * 订阅一次的事件
   * @param eventName 事件名称
   * @param listener 收听者函数
   */
  once(eventName: symbol, listener: EventHandler) {
    const handler = (...args: any[]) => {
      listener(...args)
      this.off(eventName, handler)
    }
    this.on(eventName, handler)
  }
}

export default new EventEmitter()
